<!-- 角色管理 -->
<template>
    <div class="role-box">
        <!-- 查询 -->
        <el-form :inline="true" ref="roleRuleFormRef" :model="roleRuleForm" label-width="120px" class="demo-ruleForm"
            :size="formSize" status-icon>
            <el-form-item label="角色名称" prop="roleName">
                <el-input v-model.trim="roleRuleForm.roleName" placeholder="请选择角色名称" />
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="userSubmitForm(roleRuleFormRef)">查询</el-button>
                <el-button @click="resetForm(roleRuleFormRef)">重置</el-button>
            </el-form-item>
        </el-form>

        <!-- 主体 -->
        <div class="table-but mb-5 mt-5">
            <el-button type="primary" @click="createRole">创建</el-button>
        </div>
        <!-- 表格数据 -->
        <div class="table-box">
            <el-table :data="tableData" style="width: 100%">
                <!-- 表格标题 -->
                <el-table-column :label="item.label" :prop="item.property" :formatter="item.formatter"
                    :width="item.width" v-for="(item, index) in columns" :key="index" />
                <el-table-column align="center" label="操作" width="250px">
                    <template #default="scope">
                        <el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
                        <el-button size="small" type="primary" @click="setPermission(scope.row)">设置权限</el-button>
                        <el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
            <!-- 分页 -->
            <div class="flex justify-center items-center mt-5">
                <el-pagination v-model:currentPage="pager.currentPage" v-model:page-size="pager.pageSize"
                    :page-sizes="[1, 3, 5, 10]" :small="small" :disabled="disabled" :background="background"
                    layout="total, sizes, prev, pager, next, jumper" :total="pager.total"
                    @size-change="handleSizeChange" @current-change="handleCurrentChange" />
            </div>
            <!-- 对话框-创建角色 -->
            <el-dialog v-model="dialogVisible" :title="active == 'create' ? '创建' : '编辑'" width="50%" draggable
                @close="dialogClose">
                <div>
                    <el-form ref="DialogRuleFormRef" :model="DialogRuleForm" :rules="rules" label-width="80px"
                        class="demo-ruleForm" :size="formSize" status-icon>
                        <el-form-item label="角色名" prop="roleName">
                            <el-input v-model="DialogRuleForm.roleName" placeholder="请输入您的角色名" />
                        </el-form-item>
                        <el-form-item label="备注" prop="remark">
                            <el-input v-model="DialogRuleForm.remark" placeholder="请输入备注内容" />
                        </el-form-item>
                    </el-form>
                </div>
                <template #footer>
                    <span class="dialog-footer">
                        <el-button @click="dialogVisible = false">取消</el-button>
                        <el-button type="primary" @click="DialogSubmitForm(DialogRuleFormRef)">确定</el-button>
                    </span>
                </template>
            </el-dialog>
            <!-- 对话框-设置权限 -->
            <el-dialog v-model="permissionDialogVisible" title="设置权限" width="50%" draggable @close="dialogClose">
                <div>
                    <div class="mb-3 text-lg font-bold">
                        角色名称：{{ rolename }}
                    </div>
                    <el-tree ref="treeRef" :data="roleData" show-checkbox node-key="_id" default-expand-all
                        :props="defaultProps" />
                </div>
                <template #footer>
                    <span class="dialog-footer">
                        <el-button @click="permissionDialogVisible = false">取消</el-button>
                        <el-button type="primary" @click="permissionSubmitForm">确定</el-button>
                    </span>
                </template>
            </el-dialog>
        </div>
    </div>
</template>

<script setup lang="ts">
import { nextTick, onMounted, reactive, ref } from 'vue'
import type { FormInstance } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
// import { validateMobile } from '../../utils/vaildate'
import api from '../../api'

onMounted(() => {
    getrolelistapi()
    getmenulistapi()
})
// 获取到对话框角色的数据
const getrolelistapi = (obj?: any) => {
    api.getRoleListApi({ ...obj, ...pager }).then((res: any) => {
        let { list, total } = res
        tableData.value = list//用户列表
        pager.total = total//总数据数量
    })
}
// 获取到左侧导航栏的数据
const getmenulistapi = (obj?: any) => {
    api.getMenuListApi(obj).then((res) => {
        roleData.value = res
        getActionMap(res)//获取二级菜单做字典映射
    })
}



// 头部查询
const formSize = ref('default')//用于控制该表单内组件的尺寸
const roleRuleFormRef = ref<FormInstance>()//获取ref节点
//查询的数据
const roleRuleForm = reactive({
    roleName: '',
})

//查询按钮
const userSubmitForm = async (formEl: FormInstance | undefined) => {
    if (!formEl) return
    await formEl.validate((valid, fields) => {
        if (valid) {
            // 调用角色列表接口
            getrolelistapi(roleRuleForm)
        } else {
            console.log('error submit!', fields)
        }
    })
}
//重置按钮
const resetForm = (formEl: FormInstance | undefined) => {
    if (!formEl) return
    formEl.resetFields()
}



// 表格操作按钮(对话框-创建角色)
const dialogVisible = ref(false)//对话框开关
const active = ref('create')//判断对话框是添加还是编辑
const DialogRuleFormRef = ref<FormInstance>()//获取ref节点
// 提交表单数据
const DialogRuleForm = reactive({
    roleName: '',
    remark: ''
})


// 对话框-创建角色  表单验证
const rules = reactive({
    roleName: [
        {
            required: true,
            message: '请输入角色名',
            trigger: 'blur',
        },
        {
            min: 2,
            max: 10,
            message: '角色名长度在2-10之间',
            trigger: 'blur',
            informType: 'warning',
        },
    ],
})
//确定按钮(创建/编辑)
const DialogSubmitForm = async (formEl: FormInstance | undefined) => {
    if (!formEl) return
    await formEl.validate((valid, fields) => {
        if (valid) {
            let params: any = DialogRuleForm
            //判断是新增还是编辑
            params.active = active.value
            //调用新增/编辑用户接口
            api.getRoleOperateApi(params).then(res => {
                if (res) {
                    //关闭对话框
                    dialogVisible.value = false
                    // 调用全部角色列表接口
                    getrolelistapi()
                }
            })
        } else {
            console.log('error submit!', fields)
        }
    })
}
//对话框关闭回调
const dialogClose = () => {
    //重置表单数据
    resetForm(DialogRuleFormRef.value)
}



//创建按钮
const createRole = () => {
    dialogVisible.value = true//开启对话框
    active.value = 'create'//新增状态
}


// 主体表格
const tableData: any = ref()// 表单数据
// 表格标题
const columns = [
    {
        label: '角色名称',
        property: 'roleName'
    },
    {
        label: '备注',
        property: 'remark'
    },
    {
        label: '权限列表',
        property: 'permissionList',
        width: '300px',
        formatter: function (_row: any, _column: any, cellValue: any, _index: any) {
            let { halfCheckkeys } = cellValue;//解构出对应角色的二级菜单权限
            let arr: any = []//创建空数组准备返回数据
            if (halfCheckkeys) {
                halfCheckkeys.forEach((item: any) => {
                    if (actionmap.value[item]) {//如果item为一级菜单的id则为undefined   从而获取对应的二级菜单
                        arr.push(actionmap.value[item])//遍历每一项作为属性名，获取对应的值添加到arr数组
                    }
                });
            }
            return arr.join('/')//转为字符串返回
        }
    },
    {
        label: '更新时间',
        property: 'updateTime',
        // width: '210px',
    },
    {
        label: '创建时间',
        property: 'createTime',
        // width: '210px',
    },
]
// 单个编辑
const handleEdit = (row: any) => {
    active.value = 'edit'//编辑状态
    nextTick(() => {    //nextTick:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法，获取更新后的 DOM。(重置表单数据)
        Object.assign(DialogRuleForm, row)//将当前行的数据赋值给表单    Object.assign()合并/覆盖对象
    })
    dialogVisible.value = true//开启对话框
}
// 设置权限
const setPermission = (row: any) => {
    rolename.value = row.roleName//获取选中的角色名称
    roleId.value = row._id//获取选中的角色Id
    permissionDialogVisible.value = true//开启对话框-设置权限
    setTimeout(() => {//防止页面还没渲染完成就执行setCheckedKeys
        if (row.permissionList.checkkeys) {//判断该角色是否有权限
            treeRef.value.setCheckedKeys(row.permissionList.checkkeys, false)//勾选对应的权限
        } else {
            treeRef.value.setCheckedKeys([]);//为了清缓存,什么都不勾选
        }
    }, 10)
}
// 单个删除
const handleDelete = (row: User) => {
    ElMessageBox.confirm(
        '您确定要删除吗?',
        '提示',
        {
            confirmButtonText: '是',
            cancelButtonText: '否',
            type: 'warning',
            draggable: true,//属性为true以做到拖拽
        }
    )
        .then(() => {
            // 调用删除数据接口
            api.getRoleDeleteApi({ _id: row._id }).then(res => {
                if (res) {
                    // 调用全部角色列表接口
                    getrolelistapi()
                    ElMessage({
                        type: 'success',
                        message: '删除成功',
                    })
                }
            })
        })
        .catch(() => {
            ElMessage({
                type: 'info',
                message: '已取消删除',
            })
        })
}


// 对话框-设置权限
const permissionDialogVisible = ref(false)//对话框开关
let rolename = ref()//表单顶    部的角色名称
let roleId = ref()//设置权限的角色id
const treeRef = ref()//获取标签组件Dom节点
// 确定按钮(设置权限)
const permissionSubmitForm = () => {
    // let nodes = treeRef.value.getCheckedKeys()//获取所有全选的节点的key值(包括选中的节点key值)
    // let halfkeys = treeRef.value.getHalfCheckedNodes()//获取所有半选的节点对象
    let nodes = treeRef.value.getCheckedNodes()//获取所有全选的节点对象(包括选中的节点对象)
    let halfkeys = treeRef.value.getHalfCheckedKeys()//获取所有半选的节点的key值
    let checkkeys: any = []//按钮的id数组
    let parentkeys: any = []//菜单的id数组
    nodes.forEach((node: any) => {
        if (!node.children) {
            //按钮
            checkkeys.push(node._id)
        } else {
            //菜单
            parentkeys.push(node._id)
        }
    });
    //准备传的参数
    let params: any = {
        _id: roleId.value,//角色id
        permissionList: {
            checkkeys: checkkeys,//全选的按钮id数组
            // concat()合并两个或多个数组。此方法不会更改现有数组，而是返回一个新数组。
            halfCheckkeys: halfkeys.concat(parentkeys)//半选的按钮id数组+全选的菜单id数组
        }
    }
    //调用设置权限接口
    api.setRoleAuthApi(params).then((res: any) => {
        if (res) {
            ElMessage({
                type: 'success',
                message: '设置成功',
            })
            permissionDialogVisible.value = false//关闭对话框-设置权限
            getrolelistapi()//重新获取角色列表

        }
    })
}
//所有的二级菜单的映射
const actionmap: any = ref({})
//映射出二级菜单(递归出二级菜单)
const getActionMap = (list: any) => {
    const deep = (data: any) => {
        while (data.length) {//while循环，当data有值时执行
            let item = data.pop()//移除并返回数组最后一个元素
            if (item.children && item.action) {//一级菜单
                deep(item.children)//递归继续遍历子节点
            } else {//二级菜单
                actionmap.value[item._id] = item.menuName//映射完成，二级菜单的id为键，菜单名称为值
            }
        }
    }
    //深拷贝list数组
    deep(JSON.parse(JSON.stringify(list)))
}
//树形菜单配置选项
const defaultProps = {
    children: 'children',
    label: 'menuName',
}
// 角色列表
const roleData = ref()


//分页
const pager = reactive({
    currentPage: 1,//初始化为第1页
    pageSize: 10,//一页多少条数据
    total: 0,//总条数
})
const small = ref(false)//是否使用小型分页样式
const background = ref(false)//是否为分页按钮添加背景色
const disabled = ref(false)//是否禁用分页
//一页的条数改变时触发
const handleSizeChange = (val: number) => {
    pager.pageSize = val
    getrolelistapi()
}
//当前页变动时候触发
const handleCurrentChange = (val: number) => {
    pager.currentPage = val
    getrolelistapi()
}
</script>

<style scoped lang="less">
.el-select {
    width: 200px;
}

.demo-pagination-block+.demo-pagination-block {
    margin-top: 10px;
}

.demo-pagination-block .demonstration {
    margin-bottom: 16px;
}
</style>